package com.ccrfid.rmc6.service.auth;

import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.sys.AccountEntity;
import com.ccrfid.rmc6.entity.sys.AccountRoleRelation;
import com.ccrfid.rmc6.pojo.Constants;
import com.ccrfid.rmc6.repository.sys.AccountRepository;
import com.ccrfid.rmc6.repository.sys.AccountRoleRelationRepository;
import com.ccrfid.rmc6.resource.auth.pojo.UserPrincipal;
import com.ccrfid.rmc6.util.LicenseUtil;
import com.ccrfid.rmc6.util.Md5PasswordUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Transactional
public class AuthenticationServiceImpl implements AuthenticationService {
    private static final Logger logger = LoggerFactory.getLogger(AuthenticationServiceImpl.class);
    @Autowired
    private AccountRepository accountRepository;
    @Autowired
    private AccountRoleRelationRepository accountRoleRelationRepository;
    @Value("${jwt.token.expiration}")
    private Long timeExpiration;

    @Override
    public Boolean authenticate(String userAccount, String password) throws AppException {
        int code = LicenseUtil.verifyLicense();
        if (code < 0) {
            logger.error("Application terminated! license err: {}", code);
            System.exit(-1);
        }
        AccountEntity accountEntity = accountRepository.getByUserAccount(userAccount);
        if (accountEntity == null) {
            //用户名不存在personal-alarm-records
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.account_not_fount.getCode(), CustomErrors.account_not_fount.getReason(), "");
        } else {
            //账号未启用
            if (accountEntity.getEnabled().equals(0)) {
                throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                        CustomErrors.account_disabled.getCode(), CustomErrors.account_disabled.getReason(), "");
            }
            if (Md5PasswordUtil.isPasswordValid(accountEntity.getUserPasswd(), password, userAccount)) {
                return true;
            } else {
                //密码错误
                throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                        CustomErrors.password_mistake.getCode(), CustomErrors.password_mistake.getReason(), "");
            }
        }
    }

    @Override
    public String issueToken(String userAccount) {
        AccountEntity accountEntity = accountRepository.getByUserAccount(userAccount);
        List<Long> roles = new ArrayList<>();
        List<AccountRoleRelation> relationList = accountRoleRelationRepository.getAllByAccountId(accountEntity.getId());
        if (relationList != null && relationList.size() > 0) {
            for (AccountRoleRelation relation : relationList) {
                roles.add(relation.getRoleId());
            }
        }
        Long timeNow = new Date().getTime();
        Claims claims = Jwts.claims()
                .setIssuer(Constants.issuer)
                .setExpiration(new Date(timeNow + timeExpiration));
        claims.put("userId", accountEntity.getId());
        claims.put("account", accountEntity.getUserAccount());
        claims.put("userName", accountEntity.getUserName());
        claims.put("cameraPermissionLevel", accountEntity.getCameraPermissionLevel());
        claims.put("roles", roles);
        claims.put("personnelId", accountEntity.getPersonnelId());
        claims.put("orgId", accountEntity.getOrgId());

        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS256, Constants.signKey)
                .compact();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser()
                    .requireIssuer(Constants.issuer)
                    .setSigningKey(Constants.signKey)
                    .parseClaimsJws(token);
            return true;

        } catch (JwtException ex) {
            return false;
        } catch (IllegalArgumentException ex) {
            return false;
        }
    }

    @Override
    public UserPrincipal getUserPrincipal(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(Constants.signKey)
                .parseClaimsJws(token)
                .getBody();
        Integer userId = (Integer) claims.get("userId");
        String userAccount = (String) claims.get("account");
        String userName = (String) claims.get("userName");
        Integer cameraPermissionLevel = (Integer) claims.get("cameraPermissionLevel");
        List<Long> roles = (List<Long>) claims.get("roles");
        Integer personnelId = (Integer) claims.get("personnelId");
        Integer orgId = (Integer) claims.get("orgId");
        return new UserPrincipal(Integer.toUnsignedLong(userId), userAccount, userName, cameraPermissionLevel,
                roles, personnelId == null ? null : Integer.toUnsignedLong(personnelId),
                orgId == null ? null : Integer.toUnsignedLong(orgId));
    }

    @Override
    public boolean issueIp(String userAccount, HttpServletRequest request) throws AppException {
        AccountEntity accountEntity = accountRepository.getByUserAccount(userAccount);
        String ip = getIpAddr(request);
        boolean flag = false;
        if (accountEntity == null) {
            //用户名不存在
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.account_not_fount.getCode(), CustomErrors.account_not_fount.getReason(), "");
        }
        if (accountEntity.getIp() != null && ip != null) {
            String[] ips = accountEntity.getIp().split(",");
            for (String conIp : ips) {
                if (conIp.equalsIgnoreCase("*")) {
                    flag = true;
                }
                if (!flag && conIp.equalsIgnoreCase(ip)) {
                    flag = true;
                }
            }
        }
        if (!flag) {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.ip_is_different.getCode(), CustomErrors.ip_is_different.getReason(), "");
        }
        return flag;
    }

    public String getIpAddr( HttpServletRequest request){
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        if (ip.split(",").length > 1) {
            ip = ip.split(",")[0];
        }
        return ip;
    }
}
